/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/

/**
 *
 * $Id: IMUClient.hpp,v 1.5 2009-05-18 10:33:21 morsko Exp $
 *
 * \file
 * \brief MaCI - IMU Interface Client header
 * \author Matthieu Myrsky <matthieu.myrsky@tkk.fi>
 *
 */
#ifndef _MACI_INTERFACE_IMUCLIENT_HPP_
#define _MACI_INTERFACE_IMUCLIENT_HPP_

#include "MaCI.hpp"
#include "IMUData.hpp"
#include "thread.hpp"
#include "sync.hpp"
#include "databacklog.hpp"
#include <map>



namespace MaCI {
  namespace IMU {

    /** MaCI - IMU Client interface.
     * 
     * This class contains the methods and types for using
     * a MaCI::IMU service in the GIMnet.
     */
    class CIMUClient : private gim::CSync,
                       private gim::CThread,
                       public MaCI::CMaCI
    {
    public:

      /** Constructor.
       * 
       * Constructor of the IMUClient. This requires;
       * a pointer to Initialized and connected GIMI, minor
       * number of this interface (Used as GIMI minor number)
       *
       * @param[in] aGIMIPtr Pointer to GIMI used for communication
       * @param[in] aInterfaceMinor Interface minor number. Usually
       *            used to indicate the instance of devices of same
       *            type.
       */     
      CIMUClient(gimi::GIMI *aGIMIPtr, const int aInterfaceMinor);

      
      /** Destructor.
       */
      ~CIMUClient();
      /** Open client interface.
       */
      EMaCIError DoOpen(void);


      /** Close client interface.
       */
      EMaCIError DoClose(void);

      /**
       * Gets Accelerations sent by the server.
       *
       * @param[out] aAcceleration      Acceleration values are copied here on succesfull call.
       * @param[out] aTimestamp         Timestamp values are copied here (if available from server)
       * @param aSeq                    Pointer to sequence number. If this is NULL,
       *                                the most recent acceleration values are returned immediately.
       *                                If this is not NULL, the value pointed
       *                                should be set to -1 on the first call to this function.
       *                                After each call, the sequence number of the returned
       *                                data is stored here. If user wants to read all the
       *                                measures available, this value should not be
       *                                modified after the first call.
       * @param[in] aTimeout_ms         Timeout value. If the operation is not completed
       *                                before timeout is reached, the operation fails.
       * @return                        true - Operation was succesfull, new data is copied
       *                                to provided location.
       *                                false - Operation failed; timeout or generic error
       *                                encountered.
       */
      bool GetAccelerations(TAcceleration3d &aAcceleration,
                            MaCI::Common::TTimestamp &aTimestamp,
                            int *aSeq=NULL, 
                            int aTimeout_ms=-1);

      /**
       * Gets acceleration values from backlog by timestamp.
       *
       * @param[out] aAcceleration      Accelerations are copied here on succesfull call.
       * @param[out] aTimestamp         Timestamp values are copied here (if available from server)
       * @param[in] aTime               Use \p aTime as a selection basis. Returns accelerations
       *                                _closest_ to the timestamp given.
       * @param[out] aTimediff          If this parameter is given (!NULL), it will
       *                                be set to time difference between the given time
       *                                and closest matching acceleration time.
       * @return                        true - Operation was succesfull, new data is copied
       *                                to provided location.
       *                                false - Operation failed; timeout or generic error
       *                                encountered.
       */
      bool GetAccelerations(TAcceleration3d &aAcceleration,
                            MaCI::Common::TTimestamp &aTimestamp,
                            MaCI::Common::TTimestamp &aTime, 
                            gim::time *aTimediff = NULL);

      /**
       * Gets AngularVelocities sent by the server.
       *
       * @param[out] aAngularVelocity   AngularVelocity values are copied here on succesfull call.
       * @param[out] aTimestamp         Timestamp values are copied here (if available from server)
       * @param aSeq                    Pointer to sequence number. If this is NULL,
       *                                the most recent rotation values are returned immediately.
       *                                If this is not NULL, the value pointed
       *                                should be set to -1 on the first call to this function.
       *                                After each call, the sequence number of the returned
       *                                data is stored here. If user wants to read all the
       *                                measures available, this value should not be
       *                                modified after the first call.
       * @param[in] aTimeout_ms         Timeout value. If the operation is not completed
       *                                before timeout is reached, the operation fails.
       * @return                        true - Operation was succesfull, new data is copied
       *                                to provided location.
       *                                false - Operation failed; timeout or generic error
       *                                encountered.
       */
      bool GetAngularVelocities(TAngularVelocity3d &aAngularVelocity,
                        MaCI::Common::TTimestamp &aTimestamp,
                        int *aSeq = NULL,
                        int aTimeout_ms = -1);

      /**
       * Gets rotation values from backlog by timestamp.
       *
       * @param[out] aAngularVelocity      AngularVelocities are copied here on succesfull call.
       * @param[out] aTimestamp            Timestamp values are copied here (if available from server)
       * @param[in] aTime                  Use \p aTime as a selection basis. Returns rotations
       *                                   _closest_ to the timestamp given.
       * @param[out] aTimediff             If this parameter is given (!NULL), it will
       *                                   be set to time difference between the given time
       *                                   and closest matching rotation time.
       * @return                           true - Operation was succesfull, new data is copied
       *                                   to provided location.
       *                                   false - Operation failed; timeout or generic error
       *                                   encountered.
       */
      bool GetAngularVelocities(TAngularVelocity3d &aAngularVelocity,
                               MaCI::Common::TTimestamp &aTimestamp,
                               MaCI::Common::TTimestamp &aTime, 
                               gim::time *aTimediff = NULL);

      /**
       * Gets Angle values sent by the server.
       *
       * @param[out] aAngle             Angle values are copied here on succesfull call.
       * @param[out] aTimestamp         Timestamp values are copied here (if available from server)
       * @param aSeq                    Pointer to sequence number. If this is NULL,
       *                                the most recent angle values are returned immediately.
       *                                If this is not NULL, the value pointed
       *                                should be set to -1 on the first call to this function.
       *                                After each call, the sequence number of the returned
       *                                data is stored here. If user wants to read all the
       *                                measures available, this value should not be
       *                                modified after the first call.
       * @param[in] aTimeout_ms         Timeout value. If the operation is not completed
       *                                before timeout is reached, the operation fails.
       * @return                        true - Operation was succesfull, new data is copied
       *                                to provided location.
       *                                false - Operation failed; timeout or generic error
       *                                encountered.
       */
      bool GetAngles(TAngle3d &aAngle,
                     MaCI::Common::TTimestamp &aTimestamp,
                     int *aSeq = NULL,
                     int aTimeout_ms = -1);

      /**
       * Gets angle values from backlog by timestamp.
       *
       * @param[out] aAngle         Angles are copied here on succesfull call.
       * @param[out] aTimestamp     Timestamp values are copied here (if available from server)
       * @param[in] aTime           Use \p aTime as a selection basis. Returns angles
       *                            _closest_ to the timestamp given.
       * @param[out] aTimediff      If this parameter is given (!NULL), it will
       *                            be set to time difference between the given time
       *                            and closest matching angles time.
       * @return                    true - Operation was succesfull, new data is copied
       *                            to provided location.
       *                            false - Operation failed; timeout or generic error
       *                            encountered.
       */
      bool GetAngles(TAngle3d &aAngle,
                     MaCI::Common::TTimestamp &aTimestamp,
                     MaCI::Common::TTimestamp &aTime, 
                     gim::time *aTimediff = NULL);

      /**
       * Gets Quaternion values sent by the server.
       *
       * @param[out] aQuaternion        Quaternion values are copied here on succesfull call.
       * @param[out] aTimestamp         Timestamp values are copied here (if available from server)
       * @param aSeq                    Pointer to sequence number. If this is NULL,
       *                                the most recent quaternion values are returned immediately.
       *                                If this is not NULL, the value pointed
       *                                should be set to -1 on the first call to this function.
       *                                After each call, the sequence number of the returned
       *                                data is stored here. If user wants to read all the
       *                                measures available, this value should not be
       *                                modified after the first call.
       * @param[in] aTimeout_ms         Timeout value. If the operation is not completed
       *                                before timeout is reached, the operation fails.
       * @return                        true - Operation was succesfull, new data is copied
       *                                to provided location.
       *                                false - Operation failed; timeout or generic error
       *                                encountered.
       */
      bool GetQuaternion(TQuaternion &aQuaternion, 
                         MaCI::Common::TTimestamp &aTimestamp,
                         int *aSeq = NULL, 
                         int aTimeout_ms = -1);
      /**
       * Gets quaternion values from backlog by timestamp.
       *
       * @param[out] aQuaternion    Quaternion is copied here on succesfull call.
       * @param[out] aTimestamp     Timestamp values are copied here (if available from server)
       * @param[in] aTime           Use \p aTime as a selection basis. Returns quaternion
       *                            _closest_ to the timestamp given.
       * @param[out] aTimediff      If this parameter is given (!NULL), it will
       *                            be set to time difference between the given time
       *                            and closest matching quaternion time.
       * @return                    true - Operation was succesfull, new data is copied
       *                            to provided location.
       *                            false - Operation failed; timeout or generic error
       *                            encountered.
       */
      bool GetQuaternion(TQuaternion &aQuaternion,
                         MaCI::Common::TTimestamp &aTimestamp,
                         MaCI::Common::TTimestamp &aTime, 
                         gim::time *aTimediff = NULL);

      /**
       * Gets an Orientation matrix sent by the server.
       *
       * @param[out] aOrientationMatrix Orientation matrix is copied here on succesfull call.
       * @param[out] aTimestamp         Timestamp values are copied here (if available from server)
       * @param aSeq                    Pointer to sequence number. If this is NULL,
       *                                the most recent orientation matrix is returned immediately.
       *                                If this is not NULL, the value pointed
       *                                should be set to -1 on the first call to this function.
       *                                After each call, the sequence number of the returned
       *                                data is stored here. If user wants to read all the
       *                                measures available, this value should not be
       *                                modified after the first call.
       * @param[in] aTimeout_ms         Timeout value. If the operation is not completed
       *                                before timeout is reached, the operation fails.
       * @return                        true - Operation was succesfull, new data is copied
       *                                to provided location.
       *                                false - Operation failed; timeout or generic error
       *                                encountered.
       */
      bool GetOrientationMatrix(TOrientationMatrix &aOrientationMatrix,
                                MaCI::Common::TTimestamp &aTimestamp,
                                int *aSeq = NULL, 
                                int aTimeout_ms = -1);
      /**
       * Gets Orientation matrix values from backlog by timestamp.
       *
       * @param[out] aOrientationMatrix Orientation matrix is copied here on succesfull call.
       * @param[out] aTimestamp         Timestamp values are copied here (if available from server)
       * @param[in] aTime               Use \p aTime as a selection basis. Returns orientation matrix
       *                                _closest_ to the timestamp given.
       * @param[out] aTimediff          If this parameter is given (!NULL), it will
       *                                be set to time difference between the given time
       *                                and closest matching orientation matrix time.
       * @return                        true - Operation was succesfull, new data is copied
       *                                to provided location.
       *                                false - Operation failed; timeout or generic error
       *                                encountered.
       */
      bool GetOrientationMatrix(TOrientationMatrix &aOrientationMatrix,
                                MaCI::Common::TTimestamp &aTimestamp,
                                MaCI::Common::TTimestamp &aTime, 
                                gim::time *aTimediff = NULL);
   

 private:
      // Gets the types which is sent continuously by server
      bool GetEventTypes();

      /// Thread runner function. Is in charge of receiving events.
      int ThreadFunction(const int aThreadNumber);
      int ProcessMessage(const gimi::GIMIMessage &msg); ///< Incoming data processor function

      /// Last iIMUData is stored here.
      int iAccelerationDataSequence;
      int iAngularVelocityDataSequence;
      int iAngleDataSequence;
      int iQuaternionDataSequence;      
      int iOrientationMatrixDataSequence;
      int iEventSequence;
      int iCmdSequence;

      // Types which is sent continuously by server.
      unsigned int iContinuousTypes;

      ///Data
      CIMUData iAcceleration;
      CIMUData iAngularVelocity;
      CIMUData iAngle;
      CIMUData iQuaternion;
      CIMUData iOrientationMatrix;
      CIMUData iEvent;


      // Backlog
      gim::CDataBacklog<CIMUData> iAccelerationBacklog;
      gim::CDataBacklog<CIMUData> iAngularVelocityBacklog;
      gim::CDataBacklog<CIMUData> iAngleBacklog;
      gim::CDataBacklog<CIMUData> iQuaternionBacklog;      
      gim::CDataBacklog<CIMUData> iOrientationMatrixBacklog;

    };


 }
}





#endif ///< _MACI_INTERFACE_IOCLIENT_HPP_

